package com.hyper_yang._03_designpatterns.pattern.creational_patterns;

/**
 * projectName: com.hyper_yang._03_designpatterns.pattern.creational_patterns
 *
 * @author: sakiko
 * time: 2025/9/29 3:40
 * description: 单例模式
 * 饿汉式 Eager Initialization: 【类加载】就会导致该单实例对象被【创建】
 * 该方式在成员位置声明 Singleton类型的静态变量，并创建对象实例。该对象实例是随着类的加载而创建的，如果对象足够大而一直没有使用的话会造成内存的浪费
 * 懒汉式 Lazy Initialization: 类加载不会导致该单实例对象被创建，而是【首次使用】该对象时才会【创建】
 */
public class SingletonPattern {
    public static void main(String[] args) {
        // 1、饿汉式(静态成员变量)
        EagerSingleton instance = EagerSingleton.getInstance();
        EagerSingleton instance2 = EagerSingleton.getInstance();
        System.out.println(instance == instance2);
        // 2、饿汉式(静态代码块)
        EagerSingleton2 instance3 = EagerSingleton2.getInstance();
        EagerSingleton2 instance4 = EagerSingleton2.getInstance();
        System.out.println(instance3 == instance4);
        // 3、懒汉式(线程安全、双重检查锁)
        LazySingleton instance5 = LazySingleton.getInstance();
        LazySingleton instance6 = LazySingleton.getInstance();
        System.out.println(instance5 == instance6);
        // 4、懒汉式(静态内部类)
        LazySingleton2 instance7 = LazySingleton2.getInstance();
        LazySingleton2 instance8 = LazySingleton2.getInstance();
        System.out.println(instance7 == instance8);
        // 5、饿汉式(枚举方式实现)
        EagerSingleton3 instance9 = EagerSingleton3.INSTANCE;
        EagerSingleton3 instance10 = EagerSingleton3.INSTANCE;
        System.out.println(instance9 == instance10);

        // todo: 破坏单例模式 --> 使定义的单例类可以创建多个对象，美剧方式除外 【方式: 序列化 | 反射】
    }
}

// fixme: 不建议按以下命名方式，类的命名应该描述其职责，而"懒汉式"、"饿汉式"类的内部实现等决策，应隐藏在类的封装之后
// 饿汉式 1、静态成员变量
class EagerSingleton {

    // 1、私有化构造方法 (外界访问不到就无法创建)
    private EagerSingleton() {

    }

    // 2、在本类中创建本类对象
    private static EagerSingleton instance = new EagerSingleton();

    // 3、提供公共的访问方式，让外界获取该对象 (不能创建只能调用静态方法)
    public static EagerSingleton getInstance() {
        return instance;
    }
}

// 饿汉式 2、静态代码块
class EagerSingleton2 {

    // 1、私有化构造方法
    private EagerSingleton2() {

    }

    // 2、声明本类类型的变量
    private static EagerSingleton2 instance; // 初始值 null

    // 3、在静态代码块中进行赋值
    static {
        instance = new EagerSingleton2();
    }

    // 4、提供外部访问
    public static EagerSingleton2 getInstance() {
        return instance;
    }
}

// 饿汉式 3、枚举方式 (不考虑内存空间浪费的情况下首选)
// 枚举类型线程安全、只装载一次、写法简单
enum EagerSingleton3 {
    INSTANCE;
}

// 懒汉式 (线程安全)
class LazySingleton {
    // 1、私有化构造方法
    private LazySingleton() {

    }

    // 2、声明本类类型的变量
    private static volatile LazySingleton instance; // volatile 保证可见性、有序性，预防可能存在指令重排导致的空指针问题

    // 3、提供外部访问
    public static LazySingleton getInstance() {
        if (instance == null) // 双重检查锁模式
            synchronized (LazySingleton.class) {
                if (instance == null)
                    instance = new LazySingleton();
            }
        return instance;
    }
}

// 懒汉式 2、静态内部类
// JVM的类加载机制保证了静态内部类的静态变量只会被初始化一次。
// JVM在加载外部类的过程中，不会加载静态内部类，只有内部类的属性/方法被调用时才会被加载，并初始化其静态属性
class LazySingleton2 {
    // 私有构造方法
    private LazySingleton2() {

    }

    // 定义一个静态内部类
    private static class SingletonHolder {
        // 在内部类中声明并初始化外部类的对象
        private static final LazySingleton2 INSTANCE = new LazySingleton2();
    }

    // 提供公共访问方式
    public static LazySingleton2 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}